import json

from flask import jsonify
from app.utils.error_codes import CommonErrors, UserErrors, AuthErrors, InternalErrors, WorkLogErrors


class AppException(Exception):
    """基础异常类"""

    def __init__(self,
                 status_code: int,  # HTTP状态码
                 error_code: str,  # 业务错误码
                 message: str,
                 log_level: str = "error",  # 日志级别
                 details: dict = None):
        super().__init__(message)
        self.status_code = status_code
        self.error_code = error_code
        self.message = message
        self.log_level = log_level
        self.details = details or {}

    def __str__(self):
        """控制打印输出"""
        return f"「{self.message} - moreDetails: {json.dumps(self.details, ensure_ascii=False)}」"

    def to_response(self):
        """将异常转化为API响应格式"""
        return jsonify({
            "error_code": self.error_code,
            "message": self.message,
            "msg": self.details.get('u-facingMsg', None)
            # "details": self.details
        }), self.status_code

    def log(self, logger):
        """记录日志（根据级别调用不同方法）"""
        log_method = getattr(logger, self.log_level, logger.error)
        log_msg = f"[{self.error_code}] {self.message}"
        if self.details:
            log_msg += f" | Details: {self.details}"
        log_method(log_msg)

        # 记录根因异常
        if self.__cause__:
            logger.opt(exception=self.__cause__).error(
                f"Caused by: {type(self.__cause__).__name__}",
                exc_info=self.__cause__
            )


# ----------------------------
# 通用错误异常类 (00)
# ----------------------------
class InvalidJsonError(AppException):
    """
    无效的JSON格式异常

    Args:
        details (dict): 详细信息
    """

    def __init__(self, details=None):
        super().__init__(
            status_code=400,
            error_code=CommonErrors.INVALID_JSON,
            message="无效的JSON格式",
            log_level="warning",
            details=details
        )


class MissingParamError(AppException):
    """
    缺少必要参数异常

    Args:
        param_name (str): 缺少的参数名称
    """

    def __init__(self, param_name: str):
        super().__init__(
            status_code=400,
            error_code=CommonErrors.MISSING_PARAM,
            message="缺少必要参数",
            log_level="warning",
            details={"missing_param": param_name}
        )


class IllegalTimeError(AppException):
    """
    时间非法异常

    Args:
        details (dict): 详细信息
    """

    def __init__(self, details=None):
        super().__init__(
            status_code=400,
            error_code=CommonErrors.ILLEGAL_TIME,
            message="时间非法",
            log_level="warning",
            details=details
        )


class InvalidParameterError(AppException):
    """
    传入参数无效异常

    Args:
        details: 无效参数的具体名称和值
    """

    def __init__(self, param_name):
        super().__init__(
            status_code=400,
            error_code=CommonErrors.INVALID_PARAMETER,
            message="传入参数无效或格式错误",
            log_level="warning",
            details={"invalid_param": param_name}
        )


class VersionConflictError(AppException):
    """
    版本冲突异常（数据已被其他更新）

    Args:
        resource_name: 资源名称（如"用户资料"）
        resource_id: 资源ID
    """

    def __init__(self, resource_name=None, resource_id=None):
        super().__init__(
            status_code=409,
            error_code=CommonErrors.VERSION_CONFLICT,
            message="数据已被修改，请刷新后重试",
            log_level="warning",
            details={
                "resource": resource_name,
                "resource_id": resource_id,
                "u-facingMsg": "重新加载最新数据后再提交"
            }
        )


class ResourceNotFoundError(AppException):
    """
    请求的资源不存在异常

    Args:
        resource_type: 资源类型（如"工单"、"用户"）
        resource_id: 资源标识符（如工单ID）
        extra_details: 其他详细信息
    """

    def __init__(self, resource_type="资源", resource_id=None, extra_details=None):
        details = {"resource_type": resource_type}

        if resource_id is not None:
            details["resource_id"] = resource_id

        if extra_details:
            details.update(extra_details)

        super().__init__(
            status_code=404,
            error_code=CommonErrors.RESOURCE_NOT_FOUND,
            message=f"{resource_type}不存在或已被删除",
            log_level="warning",
            details=details
        )


# ----------------------------
# 用户模块异常类 (01)
# ----------------------------
class AuthenticationFailedError(AppException):
    """
    认证失败异常（合并用户不存在和密码错误场景）

    Args:
        details: 用户登录凭证（如用户名/邮箱）
    """

    def __init__(self, details=None):
        super().__init__(
            status_code=400,
            error_code=AuthErrors.LOGIN_FAILED,
            message="用户名或密码错误",
            log_level="warning",
            details=details  # 内部记录用于审计
        )


class UserAlreadyExistsError(AppException):
    """
    用户已存在异常

    Args:
        user_id (str): 用户id
    """

    def __init__(self, user_id: str):
        super().__init__(
            status_code=409,
            error_code=UserErrors.USER_ALREADY_EXISTS,
            message="用户已存在",
            log_level="info",
            details={"user_id": user_id}
        )


class UserNotFoundError(AppException):
    """
    用户不存在异常

    Args:
        user_identifier: 用户标识信息（如用户ID、用户名等）
    """

    def __init__(self, user_identifier=None):
        super().__init__(
            status_code=404,
            error_code=UserErrors.USER_NOT_FOUND,
            message="用户不存在或已被删除",
            log_level="warning",
            details={
                "identifier": user_identifier,
                "note": "请检查用户标识是否正确",
                "u-facingMsg": "用户不存在或已被删除"
            }
        )


class InvalidRoleValueError(AppException):
    """
    非法的角色值异常

    Args:
        details (dict): 详细信息
    """

    def __init__(self, details=None):
        super().__init__(
            status_code=400,
            error_code=UserErrors.INVALID_ROLE_VALUE,
            message="非法的用户角色",
            log_level="warning",
            details=details
        )


# ----------------------------
# 认证模块异常类 (03)
# ----------------------------
class InvalidTokenError(AppException):
    """
    无效令牌异常

    Args:
        details (dict): 详细信息
    """

    def __init__(self, details):
        super().__init__(
            status_code=401,
            error_code=AuthErrors.INVALID_TOKEN,
            message="无效的身份令牌",
            log_level="warning",
            details=details
        )


class TokenExpiredError(AppException):
    """
    令牌过期异常

    Args:
        expire_at (str): 过期时间
    """

    def __init__(self, expire_at: str):
        super().__init__(
            status_code=401,
            error_code=AuthErrors.TOKEN_EXPIRED,
            message="身份令牌已过期",
            log_level="warning",
            details={"expire_time": expire_at}
        )


class MissingAuthorizationHeaderError(AppException):
    """
    缺少授权头异常

    Args:
        details (dict): 详细信息（如请求头信息等）
    """

    def __init__(self, details):
        super().__init__(
            status_code=401,
            error_code=AuthErrors.MISSING_AUTHORIZATION_HEADER,
            message="请求头中缺少授权信息",
            log_level="warning",
            details=details
        )


# ----------------------------
# 工作日志模块异常类 (04)
# ----------------------------
class WorkLogNotFoundError(AppException):
    """
    日志不存在异常

    Args:
        details (dict): 详细信息
    """

    def __init__(self, details):
        super().__init__(
            status_code=400,
            error_code=WorkLogErrors.WORK_LOG_NOT_FOUND,
            message="日志不存在",
            log_level="warning",
            details=details
        )


class InvalidUpdateFieldError(AppException):
    """
    传入更新字段无效异常

    Args:
        details (dict): 详细信息
    """

    def __init__(self, details):
        super().__init__(
            status_code=400,
            error_code=WorkLogErrors.INVALID_UPDATE_FIELD,
            message="传入更新字段无效",
            log_level="warning",
            details=details
        )


# ----------------------------
# 权限相关异常类
# ----------------------------
class PermissionDeniedError(AppException):
    """
    权限不足异常

    Args:
        resource (str): 请求的资源
        user_id (str): 用户id
    """

    def __init__(self, resource: str, user_id: str):
        super().__init__(
            status_code=403,
            error_code=AuthErrors.PERMISSION_DENIED,
            message="无权访问该资源",
            log_level="warning",
            details={"restricted_resource": resource, "user_id": user_id}
        )


# ----------------------------
# 限流异常类
# ----------------------------
class RateLimitExceededError(AppException):
    """
    请求频率超限异常

    Args:
        limit (str): 速率限制大小
    """

    def __init__(self, limit: str):
        super().__init__(
            status_code=429,
            error_code=CommonErrors.RATE_LIMIT,
            message="请求过于频繁",
            log_level="warning",
            details={"rate_limit": limit}
        )


# ----------------------------
# 内部服务模块异常类 (99)
# ----------------------------
class InternalServerError(AppException):
    """
    服务器内部错误

    Args:
        details (dict): 详细信息
    """

    def __init__(self, details=None):
        super().__init__(
            status_code=500,
            error_code=InternalErrors.INTERNAL_ERROR,
            message="服务器内部错误",
            log_level="error",
            details=details
        )


class ConfigNotFoundError(AppException):
    """
    配置文件不存在异常

    Args:
        details (dict): 详细信息
    """

    def __init__(self, details=None):
        super().__init__(
            status_code=500,
            error_code=InternalErrors.CONFIG_NOT_FOUND,
            message="配置文件不存在",
            log_level="error",
            details=details
        )


class ConfigLoadFailedError(AppException):
    """
    配置文件加载失败

    Args:
        details (dict): 详细信息
    """

    def __init__(self, details=None):
        super().__init__(
            status_code=500,
            error_code=InternalErrors.CONFIG_LOAD_FAILED,
            message="配置文件加载失败",
            log_level="error",
            details=details
        )


class InvalidConfigError(AppException):
    """
    配置文件有误

    Args:
        details (dict): 详细信息
    """

    def __init__(self, details=None):
        super().__init__(
            status_code=500,
            error_code=InternalErrors.INVALID_CONFIG,
            message="配置文件有误",
            log_level="error",
            details=details
        )


class ExportTableError(AppException):
    """
    导出表失败异常（内部处理错误）

    Args:
        details: 导出的表名称或失败详情
    """

    def __init__(self, details=None):
        super().__init__(
            status_code=500,
            error_code=InternalErrors.EXPORT_FAILED,
            message="导出表失败，请稍后重试",
            log_level="error",
            details=details
        )
